home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
The World of Computer Software.iso
/
srcuc.zip
/
UXCTTY.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-05
|
16KB
|
566 lines
/* -*-C-*-
$Header: /scheme/src/microcode/RCS/uxctty.c,v 1.11 1992/05/05 06:37:40 jinx Exp $
Copyright (c) 1990-1992 Massachusetts Institute of Technology
This material was developed by the Scheme project at the Massachusetts
Institute of Technology, Department of Electrical Engineering and
Computer Science. Permission to copy this software, to redistribute
it, and to use it for any purpose is granted, subject to the following
restrictions and understandings.
1. Any copy made of this software must include this copyright notice
in full.
2. Users of this software agree to make their best efforts (a) to
return to the MIT Scheme project any improvements or extensions that
they make, so that these may be included in future releases; and (b)
to inform MIT of noteworthy uses of this software.
3. All materials developed as a consequence of the use of this
software shall duly acknowledge such use, in accordance with the usual
standards of acknowledging credit in academic research.
4. MIT has made no warrantee or representation that the operation of
this software will be error-free, and MIT is under no obligation to
provide any services, by way of maintenance, update, or otherwise.
5. In conjunction with products arising from the use of this material,
there shall be no use of the name of the Massachusetts Institute of
Technology nor of any adaptation thereof in any advertising,
promotional, or sales literature without prior written consent from
MIT in each case. */
#include "ux.h"
#include "osctty.h"
#include "ossig.h"
/* If `ctty_fildes' is nonnegative, it is an open file descriptor for
the controlling terminal of the process.
If `ctty_fildes' is negative, Scheme should not alter the control
terminal's settings. */
static int ctty_fildes;
/* This flag says whether Scheme was in the foreground when it was
last entered. Provided that no other process forces Scheme out of
the foreground, it will remain in the foreground until it exits or
is stopped.
If `scheme_in_foreground' is zero, Scheme should not alter the
control terminal's settings, nor should it alter the settings of
stdin, stdout, or stderr if they are terminals. */
int scheme_in_foreground;
/* This flag, set during initialization, says whether we are
permitted to change the settings of the control terminal. */
static int permit_ctty_control;
/* Original states of the control terminal, stdin, and stdout when
Scheme was last continued or stopped, respectively. If the
corresponding `_recorded' flag is zero, then no information is
saved. */
struct terminal_state_recording
{
int fd;
int recorded_p;
Ttty_state state;
int flags;
};
static struct terminal_state_recording outside_ctty_state;
static struct terminal_state_recording outside_stdin_state;
static struct terminal_state_recording outside_stdout_state;
static struct terminal_state_recording inside_ctty_state;
static struct terminal_state_recording inside_stdin_state;
static struct terminal_state_recording inside_stdout_state;
static void EXFUN (ctty_update_interrupt_chars, (void));
static int
DEFUN (get_terminal_state, (fd, s), int fd AND Ttty_state * s)
{
while (1)
{
int scr = (UX_terminal_get_state (fd, s));
if ((scr >= 0) || (errno != EINTR))
return (scr);
}
}
static int
DEFUN (set_terminal_state, (fd, s), int fd AND Ttty_state * s)
{
while (1)
{
int scr = (UX_terminal_set_state (fd, s));
if ((scr >= 0) || (errno != EINTR))
return (scr);
}
}
static int
DEFUN (get_flags, (fd, flags), int fd AND int * flags)
{
#ifdef FCNTL_NONBLOCK
while (1)
{
int scr = (UX_fcntl (fd, F_GETFL, 0));
if (scr >= 0)
{
(*flags) = scr;
return (0);
}
if (errno != EINTR)
return (-1);
}
#else
return (0);
#endif
}
static int
DEFUN (set_flags, (fd, flags), int fd AND int * flags)
{
#ifdef FCNTL_NONBLOCK
while (1)
{
int scr = (UX_fcntl (fd, F_SETFL, (*flags)));
if ((scr >= 0) || (errno != EINTR))
return (scr);
}
#else
return (0);
#endif
}
static void
DEFUN (save_external_state, (s), struct terminal_state_recording * s)
{
(s -> recorded_p) =
(scheme_in_foreground
&& (isatty (s -> fd))
&& ((get_terminal_state ((s -> fd), (& (s -> state)))) >= 0)
&& ((get_flags ((s -> fd), (& (s -> flags)))) >= 0));
}
static void
DEFUN (restore_external_state, (s), struct terminal_state_recording * s)
{
if (s -> recorded_p)
{
set_terminal_state ((s -> fd), (& (s -> state)));
set_flags ((s -> fd), (& (s -> flags)));
(s -> recorded_p) = 0;
}
}
void
DEFUN (save_internal_state, (s, es),
struct terminal_state_recording * s AND
struct terminal_state_recording * es)
{
/* Don't do anything unless we have a recording of the external
state. Otherwise, we should preserve the previous recording of
the internal state, if any. */
if (es -> recorded_p)
(s -> recorded_p) =
(((get_terminal_state ((s -> fd), (& (s -> state)))) >= 0)
&& ((get_flags ((s -> fd), (& (s -> flags)))) >= 0));
}
static void
DEFUN (restore_internal_state, (s, es),
struct terminal_state_recording * s AND
struct terminal_state_recording * es)
{
/* When we recorded the internal state, we had a recording of the
external state. But since we've stopped Scheme and restarted it,
we may no longer have a current recording of the external state.
If we don't, then we can't restore the internal state.
The usual reason that we don't have a recording is that Scheme is
in the background. In that case it would be nice to preserve the
previous internal state until we go back to the foreground. But
doing that transparently would also require tracking all
attempted state changes in the recording, which is a pain. So if
we can't restore the internal state, we just thrown it away. */
if (s -> recorded_p)
{
if (es -> recorded_p)
{
set_terminal_state ((s -> fd), (& (s -> state)));
set_flags ((s -> fd), (& (s -> flags)));
}
(s -> recorded_p) = 0;
}
}
void
DEFUN_VOID (UX_ctty_save_external_state)
{
if (permit_ctty_control && (ctty_fildes >= 0))
{
pid_t pgrp_id = (UX_tcgetpgrp (ctty_fildes));
scheme_in_foreground =
((pgrp_id < 0)
/* If no job control, assume we're in foreground. */
? (errno == ENOSYS)
: ((UX_getpgrp ()) == pgrp_id));
}
else
scheme_in_foreground = 0;
save_external_state (&outside_ctty_state);
save_external_state (&outside_stdin_state);
save_external_state (&outside_stdout_state);
}
void
DEFUN_VOID (UX_ctty_restore_external_state)
{
restore_external_state (&outside_ctty_state);
restore_external_state (&outside_stdin_state);
restore_external_state (&outside_stdout_state);
}
void
DEFUN_VOID (UX_ctty_save_internal_state)
{
save_internal_state ((&inside_ctty_state), (&outside_ctty_state));
save_internal_state ((&inside_stdin_state), (&outside_stdin_state));
save_internal_state ((&inside_stdout_state), (&outside_stdout_state));
}
void
DEFUN_VOID (UX_ctty_restore_internal_state)
{
int do_update =
((inside_ctty_state . recorded_p)
&& (outside_ctty_state . recorded_p));
restore_internal_state ((&inside_ctty_state), (&outside_ctty_state));
restore_internal_state ((&inside_stdin_state), (&outside_stdin_state));
restore_internal_state ((&inside_stdout_state), (&outside_stdout_state));
if (do_update)
ctty_update_interrupt_chars ();
}
int
DEFUN_VOID (OS_ctty_interrupt_control)
{
return (outside_ctty_state . recorded_p);
}
int
DEFUN (UX_terminal_control_ok, (fd), int fd)
{
return
((fd == STDIN_FILENO)
? (outside_stdin_state . recorded_p)
: (fd == STDOUT_FILENO)
? (outside_stdout_state . recorded_p)
: 1);
}
/* Keyboard Interrupt Characters */
typedef struct
{
cc_t quit;
cc_t intrpt;
cc_t tstp;
cc_t dtstp;
} Tinterrupt_chars;
static Tinterrupt_enables current_interrupt_enables;
static Tinterrupt_chars current_interrupt_chars;
#define DEFAULT_SIGQUIT_CHAR ((cc_t) '\003') /* ^C */
#define DEFAULT_SIGINT_CHAR ((cc_t) '\007') /* ^G */
#define DEFAULT_SIGTSTP_CHAR ((cc_t) '\032') /* ^Z */
#define KEYBOARD_QUIT_INTERRUPT 0x1
#define KEYBOARD_INTRPT_INTERRUPT 0x2
#define KEYBOARD_TSTP_INTERRUPT 0x4
#define KEYBOARD_ALL_INTERRUPTS 0x7
cc_t
DEFUN_VOID (OS_ctty_quit_char)
{
return (current_interrupt_chars . quit);
}
cc_t
DEFUN_VOID (OS_ctty_int_char)
{
return (current_interrupt_chars . intrpt);
}
cc_t
DEFUN_VOID (OS_ctty_tstp_char)
{
return (current_interrupt_chars . tstp);
}
cc_t
DEFUN_VOID (OS_ctty_disabled_char)
{
return ((ctty_fildes >= 0) ? (UX_PC_VDISABLE (ctty_fildes)) : '\377');
}
int
DEFUN_VOID (OS_ctty_fd)
{
return (ctty_fildes);
}
#if 0
/* not currently used */
static void
DEFUN (ctty_get_interrupt_chars, (ic), Tinterrupt_chars * ic)
{
Ttty_state s;
if ((get_terminal_state (ctty_fildes, (&s))) == 0)
{
#ifdef HAVE_TERMIOS
(ic -> quit) = ((s . tio . c_cc) [VQUIT]);
(ic -> intrpt) = ((s . tio . c_cc) [VINTR]);
(ic -> tstp) = ((s . tio . c_cc) [VSUSP]);
#ifdef VDSUSP
(ic -> dtstp) = ((s . tio . c_cc) [VDSUSP]);
#else /* not VDSUSP */
#ifdef _HPUX
(ic -> dtstp) = (s . ltc . t_dsuspc);
#endif /* _HPUX */
#endif /* not VDSUSP */
#else /* not HAVE_TERMIOS */
#ifdef HAVE_TERMIO
(ic -> quit) = ((s . tio . c_cc) [VQUIT]);
(ic -> intrpt) = ((s . tio . c_cc) [VINTR]);
#ifdef HAVE_BSD_JOB_CONTROL
(ic -> tstp) = (s . ltc . t_suspc);
(ic -> dtstp) = (s . ltc . t_dsuspc);
#else /* not HAVE_BSD_JOB_CONTROL */
{
cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
(ic -> tstp) = disabled_char;
(ic -> dtstp) = disabled_char;
}
#endif /* not HAVE_BSD_JOB_CONTROL */
#else /* not HAVE_TERMIO */
#ifdef HAVE_BSD_TTY_DRIVER
(ic -> quit) = (s . tc . t_quitc);
(ic -> intrpt) = (s . tc . t_intrc);
#ifdef HAVE_BSD_JOB_CONTROL
(ic -> tstp) = (s . ltc . t_suspc);
(ic -> dtstp) = (s . ltc . t_dsuspc);
#else /* not HAVE_BSD_JOB_CONTROL */
{
cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
(ic -> tstp) = disabled_char;
(ic -> dtstp) = disabled_char;
}
#endif /* not HAVE_BSD_JOB_CONTROL */
#endif /* HAVE_BSD_TTY_DRIVER */
#endif /* HAVE_TERMIO */
#endif /* HAVE_TERMIOS */
}
else
{
cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
(ic -> quit) = disabled_char;
(ic -> intrpt) = disabled_char;
(ic -> tstp) = disabled_char;
(ic -> dtstp) = disabled_char;
}
}
#endif /* 0 */
static void
DEFUN (ctty_set_interrupt_chars, (ic), Tinterrupt_chars * ic)
{
Ttty_state s;
if ((get_terminal_state (ctty_fildes, (&s))) == 0)
{
#ifdef HAVE_TERMIOS
((s . tio . c_cc) [VQUIT]) = (ic -> quit);
((s . tio . c_cc) [VINTR]) = (ic -> intrpt);
((s . tio . c_cc) [VSUSP]) = (ic -> tstp);
#ifdef VDSUSP
((s . tio . c_cc) [VDSUSP]) = (ic -> dtstp);
#else /* not VDSUSP */
#ifdef _HPUX
(s . ltc . t_suspc) = (ic -> tstp);
(s . ltc . t_dsuspc) = (ic -> dtstp);
#endif /* _HPUX */
#endif /* not VDSUSP */
#else /* not HAVE_TERMIOS */
#ifdef HAVE_TERMIO
((s . tio . c_cc) [VQUIT]) = (ic -> quit);
((s . tio . c_cc) [VINTR]) = (ic -> intrpt);
#ifdef HAVE_BSD_JOB_CONTROL
(s . ltc . t_suspc) = (ic -> tstp);
(s . ltc . t_dsuspc) = (ic -> dtstp);
#endif
#else /* not HAVE_TERMIO */
#ifdef HAVE_BSD_TTY_DRIVER
(s . tc . t_quitc) = (ic -> quit);
(s . tc . t_intrc) = (ic -> intrpt);
#ifdef HAVE_BSD_JOB_CONTROL
(s . ltc . t_suspc) = (ic -> tstp);
(s . ltc . t_dsuspc) = (ic -> dtstp);
#endif
#endif /* HAVE_BSD_TTY_DRIVER */
#endif /* HAVE_TERMIO */
#endif /* HAVE_TERMIOS */
set_terminal_state (ctty_fildes, (&s));
}
}
static void
DEFUN_VOID (ctty_update_interrupt_chars)
{
if (outside_ctty_state . recorded_p)
{
cc_t disabled_char = (UX_PC_VDISABLE (ctty_fildes));
/* Must split declaration and assignment because some compilers
do not permit aggregate initializers. */
Tinterrupt_chars active_interrupt_chars;
active_interrupt_chars = current_interrupt_chars;
if ((current_interrupt_enables & KEYBOARD_QUIT_INTERRUPT) == 0)
(active_interrupt_chars . quit) = disabled_char;
if ((current_interrupt_enables & KEYBOARD_INTRPT_INTERRUPT) == 0)
(active_interrupt_chars . intrpt) = disabled_char;
if ((current_interrupt_enables & KEYBOARD_TSTP_INTERRUPT) == 0)
(active_interrupt_chars . tstp) = disabled_char;
(active_interrupt_chars . dtstp) = disabled_char;
ctty_set_interrupt_chars (&active_interrupt_chars);
}
}
void
DEFUN (OS_ctty_get_interrupt_enables, (mask), Tinterrupt_enables * mask)
{
(*mask) = current_interrupt_enables;
}
void
DEFUN (OS_ctty_set_interrupt_enables, (mask), Tinterrupt_enables * mask)
{
current_interrupt_enables = (*mask);
ctty_update_interrupt_chars ();
}
#if 0
void
DEFUN (OS_ctty_set_interrupt_chars, (quit_char, int_char, tstp_char),
cc_t quit_char AND
cc_t int_char AND
cc_t tstp_char)
{
(current_interrupt_chars . quit) = quit_char;
(current_interrupt_chars . intrpt) = int_char;
(current_interrupt_chars . tstp) = tstp_char;
ctty_update_interrupt_chars ();
}
#endif
unsigned int
DEFUN_VOID (OS_ctty_num_int_chars)
{
return (3);
}
cc_t *
DEFUN_VOID (OS_ctty_get_int_chars)
{
static cc_t int_chars [3];
int_chars[0] = current_interrupt_chars.quit;
int_chars[1] = current_interrupt_chars.intrpt;
int_chars[2] = current_interrupt_chars.tstp;
return (& int_chars [0]);
}
void
DEFUN (OS_ctty_set_int_chars, (int_chars), cc_t * int_chars)
{
current_interrupt_chars.quit = int_chars[0];
current_interrupt_chars.intrpt = int_chars[1];
current_interrupt_chars.tstp = int_chars[2];
ctty_update_interrupt_chars ();
return;
}
extern enum interrupt_handler EXFUN (OS_signal_quit_handler, (void));
extern enum interrupt_handler EXFUN (OS_signal_int_handler, (void));
extern enum interrupt_handler EXFUN (OS_signal_tstp_handler, (void));
extern void EXFUN
(OS_signal_set_interrupt_handlers,
(enum interrupt_handler quit_handler,
enum interrupt_handler int_handler,
enum interrupt_handler tstp_handler));
cc_t *
DEFUN_VOID (OS_ctty_get_int_char_handlers)
{
static cc_t int_handlers [3];
int_handlers[0] = ((cc_t) (OS_signal_quit_handler ()));
int_handlers[1] = ((cc_t) (OS_signal_int_handler ()));
int_handlers[2] = ((cc_t) (OS_signal_tstp_handler ()));
return (& int_handlers [0]);
}
void
DEFUN (OS_ctty_set_int_char_handlers, (int_handlers), cc_t * int_handlers)
{
OS_signal_set_interrupt_handlers
(((enum interrupt_handler) (int_handlers [0])),
((enum interrupt_handler) (int_handlers [1])),
((enum interrupt_handler) (int_handlers [2])));
return;
}
void
DEFUN (UX_initialize_ctty, (interactive), int interactive)
{
{
char * tty = (UX_ctermid (0));
ctty_fildes =
(((tty == 0) || ((tty[0]) == 0))
? (-1)
: (UX_open (tty, O_RDWR, 0)));
}
permit_ctty_control = interactive;
(inside_ctty_state . fd) = (outside_ctty_state . fd) = ctty_fildes;
(inside_stdin_state . fd) = (outside_stdin_state . fd) = STDIN_FILENO;
(inside_stdout_state . fd) = (outside_stdout_state . fd) = STDOUT_FILENO;
UX_ctty_save_external_state ();
(inside_ctty_state . recorded_p) = 0;
(inside_stdin_state . recorded_p) = 0;
(inside_stdout_state . recorded_p) = 0;
(current_interrupt_chars . quit) = DEFAULT_SIGQUIT_CHAR;
(current_interrupt_chars . intrpt) = DEFAULT_SIGINT_CHAR;
(current_interrupt_chars . tstp) = DEFAULT_SIGTSTP_CHAR;
(current_interrupt_chars . dtstp) = (UX_PC_VDISABLE (ctty_fildes));
current_interrupt_enables = KEYBOARD_ALL_INTERRUPTS;
if (outside_ctty_state . recorded_p)
ctty_set_interrupt_chars (¤t_interrupt_chars);
}